package com.neusoft.elmboot.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.neusoft.elmboot.exception.exceptions.ErrorStateException;
import com.neusoft.elmboot.exception.exceptions.IllegalAmountException;
import com.neusoft.elmboot.mapper.PointMapper;
import com.neusoft.elmboot.mapper.PointTransactionMapper;
import com.neusoft.elmboot.mapper.WalletMapper;
import com.neusoft.elmboot.po.dto.PointTransactionDTO;
import com.neusoft.elmboot.po.dto.UserPointTupleDTO;
import com.neusoft.elmboot.po.point.Point;
import com.neusoft.elmboot.po.point.PointMall;
import com.neusoft.elmboot.po.point.PointTransaction;
import com.neusoft.elmboot.po.point.UserPointTuple;
import com.neusoft.elmboot.po.vo.UserPointTupleVO;
import com.neusoft.elmboot.po.wallet.VirtualWallet;
import com.neusoft.elmboot.service.PointService;
import com.neusoft.elmboot.util.PointUtils;
import jakarta.annotation.Resource;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Objects;

@Service
@Transactional(rollbackFor = Exception.class)
public class PointServiceImpl extends ServiceImpl<PointMapper, Point> implements PointService {

    @Resource
    private PointMapper pointMapper;

    @Resource
    private PointTransactionMapper transactionMapper;

    @Resource
    private WalletMapper walletMapper;

    private void checkUser(String userId){
        Point point = pointMapper.selectById(userId);
        if (point == null) {
            throw new ErrorStateException("用户不存在");
        }
    }

    @Override
    public Integer init(String userId, Integer value){
        Point point = pointMapper.selectById(userId);
        if (point != null){
            throw new ErrorStateException("用户已存在");
        } else {
            transactionMapper.addTrans(new PointTransaction
                    (userId, PointUtils.OTHER_CHANNEL_ID, null, Objects.requireNonNullElse(value, 0)));
            return pointMapper.insert(new Point(userId, value));
        }
    }

    @Override
    public void addPoint(String userId, Integer channelId, String eventId, Integer amount) {
        checkUser(userId);
        if (amount <= 0) {
            throw new IllegalAmountException("参数错误");
        } else {
            pointMapper.changePoint(userId, amount);
            transactionMapper.addTrans(new PointTransaction(userId, channelId, eventId, amount));
        }
    }

    private void dealExchange(String userId, List<UserPointTupleDTO> tupleList, Integer num) {
        Point point = pointMapper.selectById(userId);
        Integer pts = point.getValue(), pts1 = pts;

        for (UserPointTupleDTO tupleDTO : tupleList){
            List<PointTransactionDTO> validTrans = transactionMapper.getValidTrans(userId);
            PointMall mall = pointMapper.getPointMall(tupleDTO.getId());
            if (mall == null) {
                throw new ErrorStateException("商品不存在");
            }
            Integer total = tupleDTO.getAmount() * mall.getPoint();

            if (pts1 >= total) {
                pts1 -= total;
                Integer total1 = total;
                for (PointTransactionDTO transactionDTO : validTrans) {
                    Integer state = transactionDTO.getState();
                    if (state <= total1){
                        total1 -= state;
                        transactionMapper.updateState(0, transactionDTO.getPtId());
                    } else {
                        state -= total1;
                        total1 = 0;
                        transactionMapper.updateState(state, transactionDTO.getPtId());
                    }

                    if (total1 == 0){
                        break;
                    }
                }
            } else {
                throw new IllegalAmountException("积分不足");
            }

            // 添加兑换记录
            UserPointTupleDTO dto = pointMapper.getUserPointTuple(userId, mall.getName());

            if (mall.getAmount() >= tupleDTO.getAmount()) {
                pointMapper.updatePointMall(mall.getId(), tupleDTO.getAmount());
            } else {
                throw new IllegalAmountException("存货不足");
            }

            if (dto == null) {
                if (tupleDTO.getAmount() <= num) {
                    UserPointTuple tuple = new UserPointTuple(userId, mall.getName(), tupleDTO.getAmount());
                    pointMapper.addUserPointTuple(tuple);
                    transactionMapper.addTrans(new PointTransaction
                            (userId, 4, null, -tuple.getAmount() * mall.getPoint()));
                } else {
                    throw new IllegalAmountException("数量异常");
                }
            } else {
                if (tupleDTO.getAmount() + dto.getCurAmount() <= num){
                    pointMapper.updateUserPointTuple(userId, mall.getName(), tupleDTO.getAmount());
                    transactionMapper.addTrans(new PointTransaction
                            (userId, 4, null, -tupleDTO.getAmount() * mall.getPoint()));
                } else {
                    throw new IllegalAmountException("数量异常");
                }
            }
        }
        pointMapper.changePoint(userId, pts1 - pts);
    }

    @Override
    public void exchange(List<UserPointTupleDTO> tupleList) {
        String userId = tupleList.get(0).getUserId();
        checkUser(userId);
        VirtualWallet wallet = walletMapper.selectById(userId);
        if (wallet.getIsVIP()) {
            dealExchange(userId, tupleList, PointUtils.VIP_MAX_AMOUNT);
        } else {
            dealExchange(userId, tupleList, PointUtils.MAX_AMOUNT);
        }
    }

    @Override
    public List<PointMall> getPointMallList() {
        return pointMapper.getPointMallList();
    }

    @Override
    public List<UserPointTupleVO> showUserPointTupleList(String userId) {
        checkUser(userId);
        return pointMapper.showUserPointTupleList(userId);
    }

    @Scheduled(cron = "0 0 4 1 * ?") //每月1号凌晨4点更新1次
    public void resetUserPointTuple(){
        try {
            pointMapper.resetUserPointTuple(); // 重置每月可兑换商品数量
            transactionMapper.delExpiredTrans(); // 删除过期的积分
        } catch (Exception e) {
            log.error("设置失败");
            log.error(e.getMessage());
        }
    }

    @Scheduled(cron = "0 0 0 * * ?") //每天0点更新一次
    public void setExpired(){
        try {
            transactionMapper.setTransExpired();
        } catch (Exception e) {
            log.error("设置失败");
            log.error(e.getMessage());
        }

    }

}
